use std::collections::HashMap;
use std::fs;

fn is_valid_id_number(id: &str) -> bool {
    let id = id.trim(); // 去除前后空格
    if id.len() != 15 && id.len() != 18 {
        return false; // 长度不为15或18位，无效
    }

    if id.len() == 15 {
        // 检查是否全是数字
        return id.chars().all(|c| c.is_digit(10));
    } else {
        // 检查前17位是否是数字，最后一位是数字或X/x
        if !id[..17].chars().all(|c| c.is_digit(10)) {
            return false;
        }
        let last_char = id.chars().nth(17).unwrap();
        if !last_char.is_digit(10) && last_char.to_ascii_uppercase() != 'X' {
            return false;
        }

        // 计算校验码
        let weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
        let check_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
        let mut sum = 0;
        for i in 0..17 {
            let digit = id.chars().nth(i).unwrap().to_digit(10).unwrap();
            sum += digit * weights[i];
        }
        let remainder = sum % 11;
        let expected_check = check_codes[remainder as usize];
        return last_char.to_ascii_uppercase() == expected_check;
    }
}

struct IdInfo {
    province: HashMap<String, String>,
    city: HashMap<String, String>,
    county: HashMap<String, String>,
}

impl IdInfo {
    fn new() -> IdInfo {
        IdInfo {
            province: IdInfo::load_file("src/province_code"),
            city: IdInfo::load_file("src/city_code"),
            county: IdInfo::load_file("src/county_code"),
        }
    }

    fn load_file(file_name: &str) -> HashMap<String, String> {
        let content = fs::read_to_string(file_name).unwrap();
        let map = content
            .lines()
            .map(|line| {
                let parts: Vec<&str> = line.splitn(2, ' ').collect();
                (parts[0].to_string(), parts[1].to_string())
            })
            .collect::<HashMap<String, String>>();
        map
    }

    fn get_province_name(&self, id: &str) -> Option<&String> {
        self.province.get(&id[..2])
    }

    fn get_city_name(&self, id: &str) -> Option<&String> {
        self.city.get(&id[..4])
    }

    fn get_county_name(&self, id: &str) -> Option<&String> {
        self.county.get(&id[..6])
    }

    fn get_gender(&self, id: &str, is_old: bool) -> &str {
        let gender = if !is_old {
            &id[16..17].parse::<usize>().unwrap()
        } else {
            &id[14..15].parse::<usize>().unwrap()
        };

        if gender % 2 == 0 {
            "女"
        } else {
            "男"
        }
    }

    fn get_birthday(&self, id: &str, is_old: bool) -> String {
        if !is_old {
            let year = &id[6..10];
            let month = &id[10..12];
            let day = &id[12..14];
            format!("{}年{:02}月{:02}日", year, month, day)
        } else {
            let year = &id[6..8];
            let month = &id[8..10];
            let day = &id[10..12];
            format!("19{}年{:02}月{:02}日", year, month, day)
        }
    }
}

pub fn check_id_card(id_card_no: &str) -> String {
    let idinfo = IdInfo::new();
    if !is_valid_id_number(id_card_no) {
        return "身份证号码错误".to_string();
    }

    let is_old = id_card_no.len() == 15;

    let province = idinfo.get_province_name(id_card_no);
    if !province.is_some() {
        return "身份证号码错误".to_string();
    }

    let city = idinfo.get_city_name(id_card_no);
    if !city.is_some() {
        return "身份证号码错误".to_string();
    }

    let county = idinfo.get_county_name(id_card_no);
    if !county.is_some() {
        return "身份证号码错误".to_string();
    }

    let gender = idinfo.get_gender(id_card_no, is_old);
    let birthday = idinfo.get_birthday(id_card_no, is_old);

    format!(
        "身份证号码正确,{},{},{}-{}-{}",
        gender,
        birthday,
        province.unwrap(),
        city.unwrap(),
        county.unwrap(),
    )
}
